// components/progress-bar/progress-bar.js
let movableAreaWidth = 0
let movableViewWidth = 0

//获取唯一的音频管理器,同时需要给它绑定事件，比如什么时候播放，什么时候暂停播放，什么时候出现错误等，都需要绑定
const backgroundAudioManager = wx.getBackgroundAudioManager()

//代表当前的秒数，目的做性能优化，因为获取的秒数太快了，比如说再53秒的时候执行了4次，那么setData就会被调用4次，如果是53那么不执行，到54时候再执行
let currentSec = -1 

let duration = 0  //当前歌曲的总时长，以秒为单位，跟totalTime是不同的，totalTime是以分钟，秒为单位

//相当于加了一把锁，为了防止onTimeUpdate事件与onChange以及onTouchEnd发生冲突，容易造成滚动条闪动的情况，而且大量操作影响性能
let isMoving = false  //表示当前进度条是否再拖拽，如果是拖拽的状态，那么不触发onTimeUpdate事件

Component({
  /**
   * 组件的属性列表
   */
  properties: { 
    isSame:Boolean
  },

  /**
   * 组件的初始数据
   */
  data: {
    //设定当前的时间
    showTime:{
      currentTime:"00:00",  //初始时长
      totalTime:"00:00",    //总体时长
    },
    movableDis:0, //移动的距离
    progress:0,   //进度条移动的距离
  },

  //声明一个对象
  lifetimes:{
    //声明一个生命周期函数，组件再页面上完成布局以后进行调用执行
    ready(){
      //进行判断，如果isSame为true并且总时长为00：00，那么重新调用_setTime方法
      if (this.properties.isSame && this.data.showTime.totalTime == "00:00") {
        this._setTime()
      }
      this._getMovableDis()
      this._bindBGMEvent()
    },
  },


  /**
   * 组件的方法列表
   */
  methods: {
    //再移动的过程中会不断的触发bindchange事件
    onChange(event){
      // console.log(event)
      //拖动结束的时候产生的值
      if (event.detail.source == 'touch') {
        //讲拖动的具体距离赋值给当前滚动条中
        this.data.progress = event.detail.x / (movableAreaWidth - movableViewWidth) * 100
        //把具体的位置赋值给移动的距离
        this.data.movableDis = event.detail.x
        //onChange代表再拖动，那么状态变为true
        isMoving = true;
      }
    },
    //拖动结束之后,this.setdata写在结束中体验好，不会产生卡顿，小程序中频繁的操作setData会造成卡顿
    onTouchEnd(){
      //获取到分钟数，容易产生小数，直接向下取整，，之后格式化，赋值给一个变量再进行调用
      const currentTimeFmt = this._dataFormat(Math.floor(backgroundAudioManager.currentTime))
      this.setData({
        progress: this.data.progress,
        movableDis: this.data.movableDis,
        ['showTime.currentTime']: currentTimeFmt.min + ':' + currentTimeFmt.sec
      })
      //把当前音乐播放到什么位置,参数以秒为设置，根据参数的设置来确定播放的位置
      //总时长 * 当前进度条的距离 / 100
      backgroundAudioManager.seek(duration * this.data.progress / 100)
      //onTouchEnd代表拖动结束了，那么把锁变为false结束掉
      //这个地方有一个小坑，就是当快速滑动的时候，会有一定的概率性重新执行一次 isMoving = true，那么就会造成再结束的时候滚动条不动的结果
      //但是始终会走onPlay播放事件，那么再onPlay播放事件中解决
      isMoving = false;
    },
    //获取进度条宽度，因为不同的设备屏幕尺寸都不同，而且也不是订死的
    _getMovableDis(){
      //会返回一个selectorQuery实例对象，能获取到宽度, 也就是创建节点查询器 query（再小程序中）
      const query = this.createSelectorQuery()
      //选择.movable-area的节点，获取节点位置信息的查询请求,获取进度条的高度以及宽度
      query.select('.movable-area').boundingClientRect()
      query.select('.movable-view').boundingClientRect()
      //此方法会执行所有的请求，会根据请求的顺序，生成一个数组
      query.exec((rect) => {
        movableAreaWidth = rect[0].width
        movableViewWidth = rect[1].width
      })
    },

    //先定义一个方法，之后再统一绑定上事件
    _bindBGMEvent(){
      //播放事件
      backgroundAudioManager.onPlay(()=>{
        console.log('onPlay')
        //每次onPlay播放事件的时候，就直接变为不拖动，相当于再次加了一把锁，解决掉概率性出现的问题
        isMoving = false

        //设置一个事件，用于点击后台播放按钮的时候，前台也跟着变化
        this.triggerEvent('musicPlay')
      })
      //停止播放事件
      backgroundAudioManager.onStop(()=>{
        console.log('onStop')
      })
      //暂停事件
      backgroundAudioManager.onPause(() => {
        console.log('onPause')

        //设置一个事件，用于点击后台暂停按钮的时候，前台也跟着变化
        this.triggerEvent('musicPause')
      })
      //监听音频正在加载当中
      backgroundAudioManager.onWaiting(() => {
        console.log('onWaiting')
      })
      //监听背景音乐可以播放的状态
      backgroundAudioManager.onCanplay(() => {
        console.log('onCanplay')
        //能获取到音乐的总时长,此时有时候会出现undefined，这是一个概率性事件，算是一个坑吧，分机器型号，解决方式判断值，值是否属于undefined
        console.log(backgroundAudioManager.duration)
        if (typeof backgroundAudioManager.duration != 'undefined') {
          //如果条件成立，那么走设置的当前时长的方法
          this._setTime()
        }else{
          //如果条件不成立，那么通过定时器的设置，过一定的时间重新获取一下
          setTimeout(()=>{
            this._setTime()
          },1000)
        }
      })
      //监听音乐播放的进度，只要小程序前台的时候才会触发，如果后台运行那就不会执行了
      backgroundAudioManager.onTimeUpdate(() => {
        // console.log('onTimeUpdate') 
        //判断，如果当前的状态没有拖动，那么进行获取滚动条的位置，如果一直再拖动，那就永不执行
        if (!isMoving) {
          //获取到当前播放的时间以及进度
          const currentTime = backgroundAudioManager.currentTime  //能够获取到当前播放时间
          const duration = backgroundAudioManager.duration  //播放的总时长

          const sec = currentTime.toString().split('.')[0]
          //currentTime返回是number类型，先转化为字符串类型，之后以“.”进行拆分，之后与设定的秒数比较，如果不等于，执行距离等条件，相等就不执行
          if (sec != currentSec) {
            console.log(currentTime)
            // console.log(currentTime) 当前获取的依旧是秒数，需要转换一下
            const currentTimeFmt = this._dataFormat(currentTime)
            //获取到移动的距离
            this.setData({
              //让总的宽度 - 移动的宽度 * 当前的时间 / 总时长
              movableDis: (movableAreaWidth - movableViewWidth) * currentTime / duration,
              //获取进度时间改变颜色,得到百分比
              progress: currentTime / duration * 100,
              //给对象中单独的属性赋值
              ['showTime.currentTime']: `${currentTimeFmt.min}:${currentTimeFmt.sec}`,
            })
            //把新的值赋给旧值
            currentSec = sec

            //联动歌词
            this.triggerEvent('timeUpdate',{
              currentTime
            })
          }
        }
      })
      //播放结束之后事件
      backgroundAudioManager.onEnded(() => {
        console.log('onCanplay')
        //当音乐结束的时候需要进入下一首，那么需要通过当初设置的按钮点击效果，但是如何触发呢？需要进行父子组件之间的传值
        //triggerEvent传递事件
        this.triggerEvent('musicEnd')
      })
      //出现错误的事件，进入此事件
      backgroundAudioManager.onError((res) => {
        console.log(res.errMsg)
        console.log(res.errCode)
        wx.showToast({
          title: '错误' + res.errCode,
        })
      })
    },

    //设置一个当前时长的方法
    _setTime(){
      //此时获取的时间是以秒为单位的，需要转换一下(外面已经定义了，所以就不用const标记了，如果外面没有，要进行标记，切记)
      duration = backgroundAudioManager.duration
      //获取格式化时间
      const durationFmt = this._dataFormat(duration)
      //渲染到页面上，但有一个问题，showTime中有2个数据，想给单独一个赋值的话，需要以数组的形式
      this.setData({
        ['showTime.totalTime']: `${durationFmt.min} : ${durationFmt.sec}`
      })
      //此时就完成了秒的赋值
      duration = duration
    },
    //格式化时间
    _dataFormat(sec){
      //分钟
      const min = Math.floor(sec / 60)
      //秒
      sec = Math.floor(sec % 60)
      return {
        'min':this._parse0(min),
        'sec':this._parse0(sec)
      }
    },

    //例子：如果是5分5秒，那么前面需要有一个0，所以再写一个方法，之后出现类似情况，直接调用方法即可
    _parse0(sec) {
      return sec < 10 ? '0' + sec : sec
    }
  }
})
